﻿using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web.Routing;
using System.Xml;
using Nop.Services;
using Nop.Services.Catalog;
using Nop.Services.Configuration;
using Nop.Services.Directory;
using Nop.Services.Media;
using Nop.Services.PromotionFeed;
using Nop.Services.Seo;
using Nop.Services.Security;
using Nop.Services.Orders;
using Nop.Services.Customers;
using Nop.Services.Payments;
using Nop.Services.Common;
using Nop.Core;
using Nop.Core.Domain;
using Nop.Core.Domain.Directory;
using Nop.Core.Plugins;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Shipping;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders;
using Nop.Core.Infrastructure;
using Nop.Core.Data;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using Nop.Plugin.Remote.Vishnu.Services;
using Nop.Plugin.Remote.Vishnu.Domain;
using Nop.Services.Authentication;

namespace Nop.Plugin.Remote.Vishnu
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class VishnuService : IVishnuService
    {
        private readonly IAddressService _addressService;
        private readonly ICountryService _countryService;
        private readonly IStateProvinceService _stateProvinceService;
        private readonly IEncryptionService _encryptionService;
        private readonly ICustomerService _customerService;
        private readonly CustomerSettings _customerSettings;
        private readonly IPermissionService _permissionSettings;
        private readonly IOrderProcessingService _OrderProcessingService;
        private readonly IOrderFlagService _OrderFlagService;
        private readonly IOrderService _orderService;
        private readonly IAuthenticationService _authenticationService;
        private readonly IWorkContext _workContext;
        private readonly IPdfService _pdfService;
        private readonly IPluginFinder _pluginFinder;
        private readonly VishnuSettings _vishnuSettings;
        public VishnuService()
        {
            _addressService = EngineContext.Current.Resolve<IAddressService>();
            _countryService = EngineContext.Current.Resolve<ICountryService>();
            _stateProvinceService = EngineContext.Current.Resolve<IStateProvinceService>();
            _encryptionService = EngineContext.Current.Resolve<IEncryptionService>();
            _customerService = EngineContext.Current.Resolve<ICustomerService>();
            _customerSettings = EngineContext.Current.Resolve<CustomerSettings>();
            _permissionSettings = EngineContext.Current.Resolve<IPermissionService>();
            _OrderProcessingService = EngineContext.Current.Resolve<IOrderProcessingService>();
            _OrderFlagService = EngineContext.Current.Resolve<IOrderFlagService>();
            _orderService = EngineContext.Current.Resolve<IOrderService>();
            _authenticationService = EngineContext.Current.Resolve<IAuthenticationService>();
            _workContext = EngineContext.Current.Resolve<IWorkContext>();
            _pdfService = EngineContext.Current.Resolve<IPdfService>();
            _pluginFinder = EngineContext.Current.Resolve<IPluginFinder>();
            _vishnuSettings = EngineContext.Current.Resolve<VishnuSettings>();
        }

        #region IVishnuService Membres

        public void CheckAccess(string usernameOrEmail, string userPassword)
        {

            if (!System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
            {
                Customer customer = null;
                if (_customerSettings.UsernamesEnabled)
                    customer = _customerService.GetCustomerByUsername(usernameOrEmail);
                else
                    customer = _customerService.GetCustomerByEmail(usernameOrEmail);

                if (customer == null || !customer.Active)
                    throw new ApplicationException("Not allowed");

                string pwd = string.Empty;
                switch (customer.PasswordFormat)
                {
                    case PasswordFormat.Encrypted:
                        pwd = _encryptionService.EncryptText(userPassword);
                        break;
                    case PasswordFormat.Hashed:
                        pwd = _encryptionService.CreatePasswordHash(userPassword, customer.PasswordSalt, _customerSettings.HashedPasswordFormat);
                        break;
                    default:
                        pwd = userPassword;
                        break;
                }

                bool isValid = pwd == customer.Password;
                if (!isValid)
                    throw new ApplicationException("Not allowed");

                //TODO surprising....
                _workContext.CurrentCustomer = customer;
                _authenticationService.SignIn(customer, true);
            }

        }

        public ServiceParameters GetParameters(string usernameOrEmail, string userPassword)
        {
            ServiceParameters param = new ServiceParameters();
            CheckAccess(usernameOrEmail, userPassword);
            param.HtmlColor = _vishnuSettings.HtmlColor;
            return param;
        }

        public System.Data.DataSet GetPaymentMethod(string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            var plugins = from p in _pluginFinder.GetPlugins<IPaymentMethod>()
                          select p;

            DataSet dataset = new DataSet();
            DataTable datatable = dataset.Tables.Add("PaymentMethod");
            datatable.Columns.Add("SystemName");
            datatable.Columns.Add("Name");
            foreach (var plugin in plugins)
            {
                datatable.LoadDataRow(new object[] { plugin.PluginDescriptor.SystemName, plugin.PluginDescriptor.FriendlyName }, true);
            }
            return dataset;
        }




        public System.Data.DataSet ExecuteDataSet(string[] sqlStatements, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            DataSet dataset = new DataSet();

            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            {
                foreach (var sqlStatement in sqlStatements)
                {
                    DataTable dt = dataset.Tables.Add();
                    SqlDataAdapter adapter = new SqlDataAdapter();
                    adapter.SelectCommand = new SqlCommand(sqlStatement, connection);
                    adapter.Fill(dt);

                }
            }

            return dataset;
        }


        public Object ExecuteScalar(string sqlStatement, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            Object result;
            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            {
                SqlCommand cmd = new SqlCommand(sqlStatement, connection);
                connection.Open();
                result = cmd.ExecuteScalar();

            }

            return result;
        }


        public void ExecuteNonQuery(string sqlStatement, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            {
                SqlCommand cmd = new SqlCommand(sqlStatement, connection);
                connection.Open();
                cmd.ExecuteScalar();
            }
        }




        public List<OrderError> DeleteOrders(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            List<OrderError> errors = new List<OrderError>();
            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    _orderService.DeleteOrder(order);
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(ex.Message);
                }
            }
            return errors;
        }
        public void AddOrderNote(int orderId, string note, bool displayToCustomer, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                order.OrderNotes.Add(new OrderNote()
                {
                    Note = note,
                    DisplayToCustomer = displayToCustomer,
                    CreatedOnUtc = DateTime.UtcNow
                });
                _orderService.UpdateOrder(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }


        public void UpdateOrderBillingInfo(int orderId, string firstName, string lastName, string phone, string email, string fax, string company, string address1, string address2,
            string city, string region, string country, string postalCode, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                Address a = order.BillingAddress;
                a.FirstName = firstName;
                a.LastName = lastName;
                a.PhoneNumber = phone;
                a.Email = email;
                a.FaxNumber = fax;
                a.Company = company;
                a.Address1 = address1;
                a.Address2 = address2;
                a.City = city;
                //a.StateProvince = region;
                a.ZipPostalCode = postalCode;
                //a.Country = country;

                _addressService.UpdateAddress(a);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }


        public void UpdateOrderShippingInfo(int orderId, string firstName, string lastName, string phone, string email, string fax, string company, string address1, string address2,
            string city, string region, string country, string postalCode, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                Address a = order.ShippingAddress;
                a.FirstName = firstName;
                a.LastName = lastName;
                a.PhoneNumber = phone;
                a.Email = email;
                a.FaxNumber = fax;
                a.Company = company;
                a.Address1 = address1;
                a.Address2 = address2;
                a.City = city;
                //a.StateProvince = region;
                a.ZipPostalCode = postalCode;
                //a.Country = country;

                _addressService.UpdateAddress(a);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


     









        public int SetOrderStatusActive(int orderId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                order.OrderStatus = OrderStatus.Pending;

                //Ces tests proviennent de la fonction CheckOrderStatus dans OrderManager
                if (order.OrderStatus == OrderStatus.Pending)
                {
                    if (order.PaymentStatus == PaymentStatus.Authorized ||
                        order.PaymentStatus == PaymentStatus.Paid)
                    {
                        order.OrderStatus = OrderStatus.Processing;
                    }
                }

                if (order.OrderStatus == OrderStatus.Pending)
                {
                    if (order.ShippingStatus == ShippingStatus.Shipped ||
                        order.ShippingStatus == ShippingStatus.Delivered)
                    {
                        order.OrderStatus = OrderStatus.Processing;
                    }
                }

                if (order.OrderStatus != OrderStatus.Cancelled &&
                    order.OrderStatus != OrderStatus.Complete)
                {
                    if (order.PaymentStatus == PaymentStatus.Paid)
                    {
                        if (!_OrderProcessingService.CanShip(order) && !_OrderProcessingService.CanDeliver(order))
                        {
                            order.OrderStatus = OrderStatus.Complete;
                        }
                    }
                }
                _orderService.UpdateOrder(order);
                return (int)order.OrderStatus;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


        public void SetOrderPaymentPending(int orderId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                order.PaymentStatus = PaymentStatus.Pending;
                _orderService.UpdateOrder(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


        public void SetOrderPaymentPaid(int orderId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                _OrderProcessingService.MarkOrderAsPaid(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


        public void SetOrderPaymentPaidWithMethod(int orderId, string paymentMethodName, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                order.PaymentMethodSystemName = paymentMethodName;
                _orderService.UpdateOrder(order);
                _OrderProcessingService.MarkOrderAsPaid(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


        public void SetOrderPaymentRefund(int orderId, bool offline, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                if (offline)
                {
                    _OrderProcessingService.RefundOffline(order);
                }
                else
                {
                    string error = string.Empty;
                    _OrderProcessingService.Refund(order);
                    if (!String.IsNullOrEmpty(error))
                    {
                        throw new ApplicationException(error);
                    }

                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }


     





        public void SetOrderShippingTracking(int orderId, string trackingNumber, bool sendShippedMail, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");


            //    try
            //    {
            //        Order order = _orderService.GetOrderById(orderId);
            //        order.TrackingNumber = trackingNumber;
            //        _orderService.UpdateOrder(order);
            //        if (sendShippedMail)
            //        {
            //            int orderShippedCustomerNotificationQueuedEmailId = EngineContext.Current.Resolve<IMessageService>().SendOrderShippedCustomerNotification(order, order.CustomerLanguageId);
            //            if (orderShippedCustomerNotificationQueuedEmailId > 0)
            //            {
            //                _orderService.InsertOrderNote(order.OrderId, string.Format("\"Shipped\" email (to customer) has been queued. Queued email identifier: {0}.", orderShippedCustomerNotificationQueuedEmailId), false, DateTime.Now);
            //            }
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        throw new ApplicationException(ex.Message);
            //    }

        }


        public void SetOrderShippingCanceled(int orderId, string usernameOrEmail, string userPassword)
        {
            throw new NotImplementedException();
        }








      

        public List<OrderError> SetOrdersStatusCanceled(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            List<OrderError> errors = new List<OrderError>();
            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    OrderFlagRecord flag = _OrderFlagService.Find(order.Id);
                    if (flag != null)
                    {
                        flag.FlagId = 0;
                        flag.FlaggedBy = usernameOrEmail;
                        flag.FlaggedOnUtc = DateTime.UtcNow;
                        _OrderFlagService.UpdateOrderFlag(flag);
                    }

                    _OrderProcessingService.CancelOrder(order, true);
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(ex.Message);
                }
            }
            return errors;
        }


        public List<OrderError> SetOrdersExportedDate(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            List<OrderError> errors = new List<OrderError>();
            using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            {

                foreach (var order in GetOrderCollection(ordersId))
                {
                    try
                    {
                        OrderFlagRecord flag = _OrderFlagService.Find(order.Id);
                        if (flag == null)
                        {
                            flag = new OrderFlagRecord();
                            flag.OrderId = order.Id;
                            flag.FlagId = 0;
                            flag.FlaggedBy = usernameOrEmail;
                            flag.FlaggedOnUtc = DateTime.UtcNow;
                            flag.ExportedBy = usernameOrEmail;
                            flag.ExportedOnUtc = DateTime.UtcNow;
                            _OrderFlagService.InsertOrderFlag(flag);
                        }
                        else
                        {
                            flag.ExportedBy = usernameOrEmail;
                            flag.ExportedOnUtc = DateTime.UtcNow;
                            _OrderFlagService.UpdateOrderFlag(flag);
                        }

                    }
                    catch (Exception ex)
                    {
                        errors.Add(new OrderError() { OrderId = order.Id, ErrorMessage = ex.Message });
                    }
                }
            }
            return errors;

        }


        public List<OrderError> SetOrdersShippingShipped(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            List<OrderError> errors = new List<OrderError>();
            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    OrderFlagRecord flag = _OrderFlagService.Find(order.Id);
                    if (flag != null)
                    {
                        flag.FlagId = 0;
                        flag.FlaggedBy = usernameOrEmail;
                        flag.FlaggedOnUtc = DateTime.UtcNow;
                        _OrderFlagService.UpdateOrderFlag(flag);
                    }


                    _OrderProcessingService.Ship(order, false);

                }
                catch (Exception ex)
                {
                    errors.Add(new OrderError() { OrderId = order.Id, ErrorMessage = ex.Message });
                }
            }
            return errors;
        }


        public List<OrderError> SetOrdersFlag(int[] ordersId, int flagId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            List<OrderError> errors = new List<OrderError>();

            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    OrderFlagRecord flag = _OrderFlagService.Find(order.Id);
                    if (flag == null)
                    {
                        flag = new OrderFlagRecord();
                        flag.OrderId = order.Id;
                        flag.FlagId = flagId;
                        flag.FlaggedBy = usernameOrEmail;
                        flag.FlaggedOnUtc = DateTime.UtcNow;
                        _OrderFlagService.InsertOrderFlag(flag);
                    }
                    else
                    {
                        flag.FlagId = flagId;
                        flag.FlaggedBy = usernameOrEmail;
                        flag.FlaggedOnUtc = DateTime.UtcNow;
                        _OrderFlagService.UpdateOrderFlag(flag);
                    }
                }
                catch (Exception ex)
                {
                    errors.Add(new OrderError() { OrderId = order.Id, ErrorMessage = ex.Message });
                }
            }
            return errors;
        }





        public string GetPdfInvoices(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            //    try
            //    {
            //        string fileName = String.Format("invoices_{0}_{1}.pdf", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"), EngineContext.Current.Resolve<IWebHelper>().GenerateRandomDigitCode(4));
            //        string filePath = String.Format("{0}files\\{1}", HttpContext.Current.Request.PhysicalApplicationPath, fileName);

            //        _pdfService.PrintInvoicesToPdf(GetOrderCollection(ordersId), filePath);

            //        return String.Format("{0}files/{1}", EngineContext.Current.Resolve<IWebHelper>().GetStoreLocation(false), fileName);
            //    }
            //    catch (Exception ex)
            //    {
            //        throw new ApplicationException(ex.Message);
            //    }

            return "";

        }



        public string GetPdfPackagingSlips(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to Manage orders");

            //    try
            //    {
            //        string fileName = String.Format("packagingslips_{0}_{1}.pdf", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"), EngineContext.Current.Resolve<IWebHelper>().GenerateRandomDigitCode(4));
            //        string filePath = String.Format("{0}files\\{1}", HttpContext.Current.Request.PhysicalApplicationPath, fileName);

            //        _pdfService.PrintPackagingSlipsToPdf(GetOrderCollection(ordersId), filePath);

            //        return String.Format("{0}files/{1}", EngineContext.Current.Resolve<IWebHelper>().GetStoreLocation(false), fileName);
            //    }
            //    catch (Exception ex)
            //    {
            //        throw new ApplicationException(ex.Message);
            //    }
            return "";

        }




        protected List<Order> GetOrderCollection(int[] ordersId)
        {
            List<Order> orders = new List<Order>();
            foreach (int id in ordersId)
            {
                orders.Add(_orderService.GetOrderById(id));
            }
            return orders;
        }

        #endregion

    }

    public class OrderError
    {
        public int OrderId { get; set; }
        public string ErrorMessage { get; set; }
    }
    public class ServiceParameters
    {
        public string HtmlColor { get; set; }
    }
}
